home *** CD-ROM | disk | FTP | other *** search
/ Gamers Delight 2 / Gamers Delight 2.iso / Aminet / game / role / ZIP_1_0.lha / src / memory.c < prev    next >
C/C++ Source or Header  |  1992-10-13  |  8KB  |  328 lines

  1. /*
  2.  * memory.c
  3.  *
  4.  * Code and data caching routines
  5.  *
  6.  * Mark Howell 28-Jul-1992 V1.0
  7.  *
  8.  */
  9.  
  10. #include "ztypes.h"
  11.  
  12. /* A cache entry */
  13.  
  14. typedef struct cache_entry {
  15.     struct cache_entry *flink;
  16.     int page_number;
  17.     zbyte_t data[PAGE_SIZE];
  18. } cache_entry_t;
  19.  
  20. /* Pages in cache and cache chain anchor */
  21.  
  22. static unsigned int cache_pages = 0;
  23. static cache_entry_t *cache = NULL;
  24.  
  25. /* Pseudo translation buffer, one entry each for code and data pages */
  26.  
  27. static unsigned int current_code_page = 0;
  28. static cache_entry_t *current_code_cachep = NULL;
  29. static unsigned int current_data_page = 0;
  30. static cache_entry_t *current_data_cachep = NULL;
  31.  
  32. #ifdef __STDC__
  33. static cache_entry_t *update_cache (int);
  34. #else
  35. static cache_entry_t *update_cache ();
  36. #endif
  37.  
  38. /*
  39.  * load_cache
  40.  *
  41.  * Initialise the cache and any other dynamic memory objects. The memory
  42.  * required can be split into two areas. Firstly, three buffers are required for
  43.  * input, output and status line. Secondly, two data areas are required for
  44.  * writeable data and read only data. The writeable data is the first chunk of
  45.  * the file and is put into non-paged cache. The read only data is the remainder
  46.  * of the file which can be paged into the cache as required. Writeable data has
  47.  * to be memory resident because it cannot be written out to a backing store.
  48.  *
  49.  */
  50.  
  51. #ifdef __STDC__
  52. void load_cache (void)
  53. #else
  54. void load_cache ()
  55. #endif
  56. {
  57.     unsigned int file_pages, data_pages;
  58.     unsigned int i;
  59.     cache_entry_t *cachep, *lastp = NULL;
  60.  
  61.     /* Allocate output, input and status line buffers */
  62.  
  63.     line = (char *) malloc (screen_cols + 1);
  64.     if (line == NULL)
  65.         fatal ("Insufficient memory to play game");
  66.     input = (char *) malloc (screen_cols + 1);
  67.     if (input == NULL)
  68.         fatal ("Insufficient memory to play game");
  69.     status_line = (char *) malloc (screen_cols + 1);
  70.     if (status_line == NULL)
  71.         fatal ("Insufficient memory to play game");
  72.  
  73.     /* Calculate dynamic cache pages required */
  74.  
  75.     file_pages = (h_file_size >> (PAGE_SHIFT - story_shift)) + 1;
  76.     data_pages = (h_data_size + PAGE_MASK) >> PAGE_SHIFT;
  77.     cache_pages = file_pages - data_pages;
  78.  
  79.     /* Allocate static data area and initialise it */
  80.  
  81.     data_size = data_pages * PAGE_SIZE;
  82.     datap = (zbyte_t *) malloc (data_size);
  83.     if (datap == NULL)
  84.         fatal ("Insufficient memory to play game");
  85.     for (i = 0; i < data_pages; i++)
  86.         read_page (i, &datap[i * PAGE_SIZE]);
  87.  
  88.     /* Allocate cache pages and initialise them */
  89.  
  90.     for (i = 0; i < cache_pages; i++) {
  91.         cachep = (cache_entry_t *) malloc (sizeof (cache_entry_t));
  92.         if (cachep == NULL) {
  93.             cache_pages = i;
  94.             i = 512 + 1;
  95.         } else {
  96.             if (i == 0)
  97.                 cache = cachep;
  98.             else
  99.                 lastp->flink = cachep;
  100.             cachep->flink = NULL;
  101.             cachep->page_number = data_pages + i;
  102.             lastp = cachep;
  103.             read_page (cachep->page_number, cachep->data);
  104.         }
  105.     }
  106.  
  107. }/* load_cache */
  108.  
  109. /*
  110.  * unload_cache
  111.  *
  112.  * Deallocate cache and other memory objects.
  113.  *
  114.  */
  115.  
  116. #ifdef __STDC__
  117. void unload_cache (void)
  118. #else
  119. void unload_cache ()
  120. #endif
  121. {
  122.     cache_entry_t *cachep, *nextp;
  123.  
  124.     /* Free output buffer, input buffer, status line and data memory */
  125.  
  126.     free (line);
  127.     free (input);
  128.     free (status_line);
  129.     free (datap);
  130.  
  131.     /* Free cache memory */
  132.  
  133.     for (cachep = cache; cachep->flink != NULL; cachep = nextp) {
  134.         nextp = cachep->flink;
  135.         free (cachep);
  136.     }
  137.  
  138. }/* unload_cache */
  139.  
  140. /*
  141.  * read_code_word
  142.  *
  143.  * Read a word from the instruction stream.
  144.  *
  145.  */
  146.  
  147. #ifdef __STDC__
  148. zword_t read_code_word (void)
  149. #else
  150. zword_t read_code_word ()
  151. #endif
  152. {
  153.     zword_t w;
  154.  
  155.     w = (zword_t) read_code_byte () << 8;
  156.     w |= (zword_t) read_code_byte ();
  157.  
  158.     return (w);
  159.  
  160. }/* read_code_word */
  161.  
  162. /*
  163.  * read_code_byte
  164.  *
  165.  * Read a byte from the instruction stream.
  166.  *
  167.  */
  168.  
  169. #ifdef __STDC__
  170. zbyte_t read_code_byte (void)
  171. #else
  172. zbyte_t read_code_byte ()
  173. #endif
  174. {
  175.     unsigned int page_number, page_offset;
  176.  
  177.     /* Calculate page and offset values */
  178.  
  179.     page_number = (unsigned int) (pc >> PAGE_SHIFT);
  180.     page_offset = (unsigned int) pc & PAGE_MASK;
  181.  
  182.     /* Load page into translation buffer */
  183.  
  184.     if (page_number != current_code_page) {
  185.         current_code_cachep = update_cache (page_number);
  186.         current_code_page = page_number;
  187.     }
  188.  
  189.     /* Update the PC */
  190.  
  191.     pc++;
  192.  
  193.     /* Return byte from page offset */
  194.  
  195.     return (current_code_cachep->data[page_offset]);
  196.  
  197. }/* read_code_byte */
  198.  
  199. /*
  200.  * read_data_word
  201.  *
  202.  * Read a word from the data area.
  203.  *
  204.  */
  205.  
  206. #ifdef __STDC__
  207. zword_t read_data_word (unsigned long *addr)
  208. #else
  209. zword_t read_data_word (addr)
  210. unsigned long *addr;
  211. #endif
  212. {
  213.     zword_t w;
  214.  
  215.     w = (zword_t) read_data_byte (addr) << 8;
  216.     w |= (zword_t) read_data_byte (addr);
  217.  
  218.     return (w);
  219.  
  220. }/* read_data_word */
  221.  
  222. /*
  223.  * read_data_byte
  224.  *
  225.  * Read a byte from the data area.
  226.  *
  227.  */
  228.  
  229. #ifdef __STDC__
  230. zbyte_t read_data_byte (unsigned long *addr)
  231. #else
  232. zbyte_t read_data_byte (addr)
  233. unsigned long *addr;
  234. #endif
  235. {
  236.     unsigned int page_number, page_offset;
  237.     zbyte_t value;
  238.  
  239.     /* Check if byte is in non-paged cache */
  240.  
  241.     if (*addr < (unsigned long) data_size)
  242.         value = datap[*addr];
  243.     else {
  244.  
  245.         /* Calculate page and offset values */
  246.  
  247.         page_number = (int) (*addr >> PAGE_SHIFT);
  248.         page_offset = (int) *addr & PAGE_MASK;
  249.  
  250.         /* Load page into translation buffer */
  251.  
  252.         if (page_number != current_data_page) {
  253.             current_data_cachep = update_cache (page_number);
  254.             current_data_page = page_number;
  255.         }
  256.  
  257.         /* Fetch byte from page offset */
  258.  
  259.         value = current_data_cachep->data[page_offset];
  260.     }
  261.  
  262.     /* Update the address */
  263.  
  264.     (*addr)++;
  265.  
  266.     return (value);
  267.  
  268. }/* read_data_byte */
  269.  
  270. /*
  271.  * update_cache
  272.  *
  273.  * Called on a code or data page cache miss to find the page in the cache or
  274.  * read the page in from disk. The chain is kept as a simple LRU chain. If a
  275.  * page cannot be found then the page on the end of the chain is reused. If the
  276.  * page is found, or reused, then it is moved to the front of the chain.
  277.  *
  278.  */
  279.  
  280. #ifdef __STDC__
  281. static cache_entry_t *update_cache (int page_number)
  282. #else
  283. static cache_entry_t *update_cache (page_number)
  284. int page_number;
  285. #endif
  286. {
  287.     cache_entry_t *cachep, *lastp;
  288.  
  289.     /* Search the cache chain for the page */
  290.  
  291.     for (lastp = cache, cachep = cache;
  292.          cachep->flink != NULL &&
  293.          cachep->page_number &&
  294.          cachep->page_number != page_number;
  295.          lastp = cachep, cachep = cachep->flink)
  296.         ;
  297.  
  298.     /* If no page in chain then read it from disk */
  299.  
  300.     if (cachep->page_number != page_number) {
  301.  
  302.         /* Reusing last cache page, so invalidate cache if page was in use */
  303.  
  304.         if (cachep->flink == NULL && cachep->page_number) {
  305.             if (current_code_page == (unsigned int) cachep->page_number)
  306.                 current_code_page = 0;
  307.             if (current_data_page == (unsigned int) cachep->page_number)
  308.                 current_data_page = 0;
  309.         }
  310.  
  311.         /* Load the new page number and the page contents from disk */
  312.  
  313.         cachep->page_number = page_number;
  314.         read_page (page_number, cachep->data);
  315.     }
  316.  
  317.     /* If page is not at front of cache chain then move it there */
  318.  
  319.     if (lastp != cache) {
  320.         lastp->flink = cachep->flink;
  321.         cachep->flink = cache;
  322.         cache = cachep;
  323.     }
  324.  
  325.     return (cachep);
  326.  
  327. }/* update_cache */
  328.